package com.meida.module.bus.provider.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.meida.common.mybatis.entity.EntityMap;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.mybatis.query.CriteriaQuery;
import com.meida.common.mybatis.query.CriteriaSave;
import com.meida.module.bus.client.entity.*;
import com.meida.module.bus.provider.api.util.ApiConstants;
import com.meida.module.bus.provider.api.util.PmsApiUtil;
import com.meida.module.bus.provider.api.util.PmsToolUtil;
import com.meida.module.bus.provider.mapper.BusMasterAlldataViewMapper;
import com.meida.module.bus.provider.service.*;
import com.meida.common.mybatis.base.service.impl.BaseServiceImpl;
import com.netflix.loadbalancer.AbstractLoadBalancerPing;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * VIEW接口实现类
 *
 * @author flyme
 * @date 2020-12-05
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class BusMasterAlldataViewServiceImpl extends BaseServiceImpl<BusMasterAlldataViewMapper, BusMasterAlldataView> implements BusMasterAlldataViewService {

    @Autowired
    private PmsApiUtil pmsApiUtil;
    @Autowired
    private BusMaterialPlan100Service plan100Service;
    @Autowired
    private BusMaterialPlan200Service plan200Service;
    @Autowired
    private BusMaterialPackage100Service package100Service;
    @Autowired
    private BusMaterialPackage200Service package200Service;

    @Override
    public ResultBody beforeAdd(CriteriaSave cs, BusMasterAlldataView bmav, EntityMap extra) {
        return ResultBody.ok();
    }


    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody beforePageList(CriteriaQuery<BusMasterAlldataView> cq, BusMasterAlldataView bmav, EntityMap requestMap) {
        cq.like(BusMasterAlldataView.class, "ver");
        cq.like(BusMasterAlldataView.class, "type");
        cq.like(BusMasterAlldataView.class, "planType");
        cq.like(BusMasterAlldataView.class, "instructNumber");
        cq.like(BusMasterAlldataView.class, "projectCode");
        cq.like(BusMasterAlldataView.class, "projectName");
        cq.like(BusMasterAlldataView.class, "majorName");
        cq.like(BusMasterAlldataView.class, "majorCode");
        cq.like(BusMasterAlldataView.class, "packageName");
        cq.like(BusMasterAlldataView.class, "packageNo");
        cq.like(BusMasterAlldataView.class, "materialWbsCode");
        cq.like(BusMasterAlldataView.class, "materialCode");
        cq.like(BusMasterAlldataView.class, "materialName");
        cq.like(BusMasterAlldataView.class, "materiaSpecs");
        cq.like(BusMasterAlldataView.class, "materialDesc");
        cq.like(BusMasterAlldataView.class, "technicalData");
        cq.like(BusMasterAlldataView.class, "serviceWbsCode");
        cq.like(BusMasterAlldataView.class, "serviceCode");
        cq.like(BusMasterAlldataView.class, "subjectName");
        cq.like(BusMasterAlldataView.class, "packageDesc");
        cq.like(BusMasterAlldataView.class, "levelNo");
        cq.like(BusMasterAlldataView.class, "contractDesc");
        cq.like(BusMasterAlldataView.class, "materialArea");
        cq.like(BusMasterAlldataView.class, "materialUse");
        cq.like(BusMasterAlldataView.class, "loss");
        cq.like(BusMasterAlldataView.class, "brandName");
        cq.like(BusMasterAlldataView.class, "remark");
//      cq.orderByDesc("bmav.createTime");
        return ResultBody.ok();
    }

    @Override
    public void afterPageList(CriteriaQuery<BusMasterAlldataView> cq, List<EntityMap> data, ResultBody resultBody) {
        data.forEach(obj -> {
            // 损耗
            obj.put("loss", formateBigDecimalForStr(obj.getBigDecimal("loss"), 0));

            String calDateBe = StrUtil.isEmpty(cq.getParams("calDateBe")) ? DateUtil.format(new Date(), "yyyy-MM") : cq.getParams("calDateBe").substring(0, 7);
            String type = (String) obj.get("type");

            Object planPackage100 = null;
            // 100版本累加用母表ID
            Long materialId100 = 0L;
            if (ApiConstants.VER_200 <= obj.getInt("ver")) {
                planPackage100 = pmsApiUtil.get100PlanPackObj(obj.getLong("packagePlanId"), type);
                if (null != planPackage100) {
                    // 100版本累加用母表ID
                    materialId100 = PmsToolUtil.getLongValue(planPackage100, ApiConstants.INVOKE_GET_MATERIALID);
                    // 100采购计划量
                    obj.put("unitBillQuantity100", PmsToolUtil.getBigDecimalValue(planPackage100, ApiConstants.INVOKE_GET_PLANPURCHASECOUNT));
                }

            }
            Integer kind = type.contains("材料") ? 0 : 1;
            // 本月
            BigDecimal completedQuantities = getCompletedQuantities(obj.getLong("materialId"), obj.getInt("ver"), calDateBe, null, null, kind);
            if (null != planPackage100) {
                completedQuantities = NumberUtil.add(completedQuantities, getCompletedQuantities(materialId100, ApiConstants.VER_100,
                    calDateBe, null, null, kind));
            }
            obj.put("currentFinishMonthCount", completedQuantities == null ? BigDecimal.ZERO : completedQuantities);

            // 累计上月
            BigDecimal completedQuantitiesLast = getCompletedQuantities(obj.getLong("materialId"), obj.getInt("ver"), null, calDateBe, StrUtil.isEmpty(cq.getParams("calDateAf")) ? null : cq.getParams("calDateAf").substring(0, 7), kind);
            if (null != planPackage100) {
                completedQuantitiesLast = NumberUtil.add(completedQuantitiesLast, getCompletedQuantities(materialId100, ApiConstants.VER_100,
                    null, calDateBe, StrUtil.isEmpty(cq.getParams("calDateAf")) ? null : cq.getParams("calDateAf").substring(0, 7), kind));
            }
            obj.put("lastFinishMonthCount", completedQuantitiesLast == null ? BigDecimal.ZERO : completedQuantitiesLast);
            obj.put("totalFinishCount", NumberUtil.add(completedQuantities, completedQuantitiesLast));

            // 本月实现产值（未税）
            // 合同价（合价）
            // 主材价 【完成工程量-本月完成工程量】*【对外合同单价-合同价（单价）-主材价】
            obj.put("currentMonthmainPrice", kind == 0 ? NumberUtil.mul(completedQuantities, obj.getBigDecimal("mainPrice3")) : BigDecimal.ZERO);
            // 安装价 【完成工程量-本月完成工程量】*【对外合同单价-合同价（单价）-安装价】
            obj.put("currentMonthinstallPrice", kind == 1 ? NumberUtil.mul(completedQuantities, obj.getBigDecimal("installPrice3")) : BigDecimal.ZERO);
            // 合计 主材价 + 安装价
            obj.put("currentMonthsumPrice", NumberUtil.add(obj.getBigDecimal("currentMonthmainPrice"), obj.getBigDecimal("currentMonthinstallPrice")));

            // 截止上月实现产值（未税）
            // 合同价（合价）
            // 主材价 【完成工程量-截止上月完成工程量】*【对外合同单价-合同价（单价）-主材价】
            obj.put("lastMonthmainPrice", kind == 0 ? NumberUtil.mul(completedQuantitiesLast, obj.getBigDecimal("mainPrice3")) : BigDecimal.ZERO);
            // 安装价 【完成工程量-截止上月完成工程量】*对外合同单价-合同价（单价）-安装价】
            obj.put("lastMonthinstallPrice", kind == 1 ? NumberUtil.mul(completedQuantitiesLast, obj.getBigDecimal("installPrice3")) : BigDecimal.ZERO);
            // 合计 主材价 + 安装价
            obj.put("lastMonthsumPrice", NumberUtil.add(obj.getBigDecimal("lastMonthmainPrice"), obj.getBigDecimal("lastMonthinstallPrice")));

            // 累计实现产值（未税）
            // 合同价（合价）
            // 主材价 【完成工程量-累计完成工程量】*【对外合同单价-合同价（单价）-主材价】
            obj.put("totalMonthmainPrice", kind == 0 ? NumberUtil.add(obj.getBigDecimal("currentMonthmainPrice"), obj.getBigDecimal("lastMonthmainPrice")) : BigDecimal.ZERO);
            // 安装价 【完成工程量-累计完成工程量】*对外合同单价-合同价（单价）-安装价】
            obj.put("totalMonthinstallPrice", kind == 1 ? NumberUtil.add(obj.getBigDecimal("currentMonthinstallPrice"), obj.getBigDecimal("lastMonthinstallPrice")) : BigDecimal.ZERO);
            // 合计 主材价 + 安装价
            obj.put("totalsumPrice", NumberUtil.add(obj.getBigDecimal("currentMonthsumPrice"), obj.getBigDecimal("lastMonthsumPrice")));

            // 合同清单工程量 * 对外合同合价_合同价_合价_合计
//            BigDecimal amountRealizedVal = NumberUtil.mul(obj.getBigDecimal("contractBillQuantity"), obj.getBigDecimal("syntheticalAmount3"));

            // 预估总产值_合同价_合价_合计
            BigDecimal contractsumSyntheticalPrice3 = obj.getBigDecimal("contractsumSyntheticalPrice3");
            if (null != contractsumSyntheticalPrice3 && BigDecimal.ZERO.compareTo(contractsumSyntheticalPrice3) < 0) {
                // 实现比列
                // 本月实现比例（%）
                // 本月实现产值未税_合同价_合价_合计/（预估总产值_合同价_合价_合计）
                obj.put("realizationRatioThisMonth", formateBigDecimalForStr(NumberUtil.div(obj.getBigDecimal("currentMonthsumPrice"), contractsumSyntheticalPrice3), 0));

                // 截至上月实现比例（%）
                // 截止上月实现产值未税_合同价_合价_合计 /（预估总产值_合同价_合价_合计）
                obj.put("asOfLastMonthsRealizationRatio", formateBigDecimalForStr(NumberUtil.div(obj.getBigDecimal("lastMonthsumPrice"), contractsumSyntheticalPrice3), 0));

                // 累计实现比例（%）
                // 累计实现产值未税_合同价_合价_合计 /（预估总产值_合同价_合价_合计）
                obj.put("cumulativeRealizationRatio", formateBigDecimalForStr(NumberUtil.div(obj.getBigDecimal("totalsumPrice"), contractsumSyntheticalPrice3), 0));

                // 理论产值（未税）
                // 本月实现金额
                // 本月实现比例 * 合同清单工程量 * 对外合同合价_合同价_合价_合计
                obj.put("amountRealizedThisMonth", formateBigDecimalForStr(NumberUtil.mul(obj.getBigDecimal("realizationRatioThisMonth"), obj.getBigDecimal("syntheticalAmount3")), 0));

                // 截至上月实现金额
                // 截止上月实现比例 * 合同清单工程量 * 对外合同合价_合同价_合价_合计
                obj.put("amountRealizedAsOfLastMonth", formateBigDecimalForStr(NumberUtil.mul(obj.getBigDecimal("asOfLastMonthsRealizationRatio"), obj.getBigDecimal("syntheticalAmount3")), 0));

                // 累计实现金额
                // 累计实现比例 * 合同清单工程量 * 对外合同合价_合同价_合价_合计
                obj.put("cumulativeRealizedAmount", formateBigDecimalForStr(NumberUtil.mul(obj.getBigDecimal("cumulativeRealizationRatio"), obj.getBigDecimal("syntheticalAmount3")), 0));
            }

        });
        EntityMap map = new EntityMap();
        map.put("data", data);
        resultBody.setExtra(map);
    }

    @Override
    public List<BusMasterAlldataView> getBusMasterAlldataViews(Map<String, Object> param) {
        Date calDate = null == param.get("calDateBe") ? new Date() : DateUtil.parse(String.valueOf(param.get("calDateBe")), "yyy-MM");
        String calDateBe = DateUtil.format(DateUtil.offset(calDate, DateField.MONTH, -1), "yyyy-MM");
        String calDateThisMonth = DateUtil.format(calDate, "yyyy-MM");

        List<BusMasterAlldataView> masterAlldataViews = this.getBaseMapper().getBusMasterAlldataViews(param);
        masterAlldataViews.stream().forEach(masterObj -> {

            String type = masterObj.getType();

            Object planPackage100 = null;
            if (ApiConstants.VER_200 <= masterObj.getVer()) {
                planPackage100 = pmsApiUtil.get100PlanPackObj(masterObj.getPackagePlanId(), type);
            }

            Integer kind = type.contains("材料") ? 0 : 1;
            // 100版本累加用母表ID
            Long materialId100 = 0L;
            if (null != planPackage100) {
                materialId100 = PmsToolUtil.getLongValue(planPackage100, ApiConstants.INVOKE_GET_MATERIALID);
            }

            // 本月
            // BigDecimal completedQuantities = BigDecimal.ZERO;
            BigDecimal completedQuantities = getCompletedQuantities(masterObj.getMaterialId(), masterObj.getVer(), calDateBe, null, null, kind);
            if (null != planPackage100) {
                completedQuantities = NumberUtil.add(completedQuantities, getCompletedQuantities(materialId100, ApiConstants.VER_100,
                    calDateBe, null, null, kind));
            }
            masterObj.setCurrentFinishMonthCount(completedQuantities);

            // 累计上月
            BigDecimal completedQuantitiesLast = getCompletedQuantities(masterObj.getMaterialId(), masterObj.getVer(), null, calDateBe, null == param.get("calDateAf") ? null : String.valueOf(param.get("calDateAf")), kind);
            if (null != planPackage100) {
                completedQuantitiesLast = NumberUtil.add(completedQuantitiesLast, getCompletedQuantities(materialId100, ApiConstants.VER_100,
                    null, calDateBe, null == param.get("calDateAf") ? null : String.valueOf(param.get("calDateAf")), kind));
            }
            masterObj.setLastFinishMonthCount(completedQuantitiesLast);
            masterObj.setTotalFinishCount(NumberUtil.add(masterObj.getCurrentFinishMonthCount(), masterObj.getLastFinishMonthCount()));

            // 本月实现产值（未税）
            // 合同价（合价）
            // 主材价 【完成工程量-本月完成工程量】*【对外合同单价-合同价（单价）-主材价】
            masterObj.setCurrentMonthmainPrice(kind == 0 ? NumberUtil.mul(completedQuantities, masterObj.getMainPrice3()) : BigDecimal.ZERO);
            // 安装价 【完成工程量-本月完成工程量】*【对外合同单价-合同价（单价）-安装价】
            masterObj.setCurrentMonthinstallPrice(kind == 1 ? NumberUtil.mul(completedQuantities, masterObj.getInstallPrice3()) : BigDecimal.ZERO);
            // 合计 主材价 + 安装价
            masterObj.setCurrentMonthsumPrice(NumberUtil.add(masterObj.getCurrentMonthmainPrice(), masterObj.getCurrentMonthinstallPrice()));

            // 截止上月实现产值（未税）
            // 合同价（合价）
            // 主材价 【完成工程量-截止上月完成工程量】*【对外合同单价-合同价（单价）-主材价】
            masterObj.setLastMonthmainPrice(kind == 0 ? NumberUtil.mul(completedQuantitiesLast, masterObj.getMainPrice3()) : BigDecimal.ZERO);
            // 安装价 【完成工程量-截止上月完成工程量】*对外合同单价-合同价（单价）-安装价】
            masterObj.setLastMonthinstallPrice(kind == 1 ? NumberUtil.mul(completedQuantitiesLast, masterObj.getInstallPrice3()) : BigDecimal.ZERO);
            // 合计 主材价 + 安装价
            masterObj.setLastMonthsumPrice(NumberUtil.add(masterObj.getLastMonthmainPrice(), masterObj.getLastMonthinstallPrice()));

            // 累计实现产值（未税）
            // 合同价（合价）
            // 主材价
            masterObj.setTotalMonthmainPrice(kind == 0 ? NumberUtil.add(masterObj.getCurrentMonthsumPrice(), masterObj.getLastMonthsumPrice()) : BigDecimal.ZERO);
            // 安装价
            masterObj.setTotalMonthinstallPrice(kind == 1 ? NumberUtil.add(masterObj.getCurrentMonthinstallPrice(), masterObj.getLastMonthinstallPrice()) : BigDecimal.ZERO);
            // 合计
            masterObj.setTotalsumPrice(NumberUtil.add(masterObj.getCurrentMonthsumPrice(), masterObj.getLastMonthsumPrice()));

            // 合同清单工程量 * 对外合同合价_合同价_合价_合计
//            BigDecimal amountRealizedVal = NumberUtil.mul(masterObj.getContractBillQuantity(), masterObj.getSyntheticalAmount3());
            BigDecimal contractsumSyntheticalPrice3 = masterObj.getContractsumSyntheticalPrice3();
            if (null != contractsumSyntheticalPrice3 && BigDecimal.ZERO.compareTo(contractsumSyntheticalPrice3) < 0) {
                // 实现比列
                // 本月实现比例（%）
                // 本月实现产值未税_合同价_合价_合计/（100版量或200版量*预估总产值_合同价_合价_合计）
                masterObj.setRealizationRatioThisMonth(NumberUtil.div(masterObj.getCurrentMonthsumPrice(), contractsumSyntheticalPrice3));

                // 截至上月实现比例（%）
                // 截止上月实现产值未税_合同价_合价_合计 /（100版量或200版量*预估总产值_合同价_合价_合计）
                masterObj.setAsOfLastMonthsRealizationRatio(NumberUtil.div(masterObj.getLastMonthsumPrice(), contractsumSyntheticalPrice3));

                // 累计实现比例（%）
                // 累计实现产值未税_合同价_合价_合计 /（100版量或200版量*预估总产值_合同价_合价_合计）
                masterObj.setCumulativeRealizationRatio(NumberUtil.div(masterObj.getTotalsumPrice(), contractsumSyntheticalPrice3));

                // 理论产值（未税）
                // 本月实现金额
                // 本月实现比例 * 合同清单工程量 * 对外合同合价_合同价_合价_合计
                masterObj.setAmountRealizedThisMonth(NumberUtil.mul(masterObj.getRealizationRatioThisMonth(), masterObj.getSyntheticalAmount3()));

                // 截至上月实现金额
                // 截止上月实现比例 * 合同清单工程量 * 对外合同合价_合同价_合价_合计
                masterObj.setAmountRealizedAsOfLastMonth(NumberUtil.mul(masterObj.getAsOfLastMonthsRealizationRatio(), masterObj.getSyntheticalAmount3()));

                // 累计实现金额
                // 累计实现比例 * 合同清单工程量 * 对外合同合价_合同价_合价_合计
                masterObj.setCumulativeRealizedAmount(NumberUtil.mul(masterObj.getCumulativeRealizationRatio(), masterObj.getSyntheticalAmount3()));
            }

        });
        return masterAlldataViews;
    }

    private String formateBigDecimalForStr(BigDecimal val, int kind) {
        if (null == val || BigDecimal.ZERO.equals(val)) {
            return "0.00%";
        }
        if (0 == kind) {
            return NumberUtil.decimalFormat("#.###", Double.valueOf(String.valueOf(val)));
        }
        return NumberUtil.decimalFormat("#.###", Double.valueOf(String.valueOf(val)));
    }

    private BigDecimal formateBigDecimal(BigDecimal val) {
        if (null == val || BigDecimal.ZERO.equals(val)) {
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(Long.valueOf(NumberUtil.decimalFormat("#.###", Double.valueOf(String.valueOf(val)))));
    }

    private BigDecimal getCompletedQuantities(Long materialId, Integer ver, String calDateThisMonth, String calDateBe, String calDateAf, Integer kind) {
        Map<String, Object> searchMap = Maps.newHashMap();
        searchMap.put("materialId", materialId);
        searchMap.put("ver", ver);
        searchMap.put("calDateThisMonth", calDateThisMonth);
        searchMap.put("calDateBe", calDateBe);
        searchMap.put("calDateAf", calDateAf);
        if (0 == kind) {
            return this.getBaseMapper().getCompeltedQuantitiesWz(searchMap);
        }
        return this.getBaseMapper().getCompeltedQuantitiesFb(searchMap);
    }

}
